home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / rogue / curses.c next >
Encoding:
C/C++ Source or Header  |  1987-05-13  |  11.3 KB  |  651 lines

  1. /*
  2.  * curses.c
  3.  *
  4.  * This source herein may be modified and/or distributed by anybody who
  5.  * so desires, with the following restrictions:
  6.  *    1.)  No portion of this notice shall be removed.
  7.  *    2.)  Credit shall not be taken for the creation of this source.
  8.  *    3.)  This code is not to be traded, sold, or used for personal
  9.  *         gain or profit.
  10.  *
  11.  */
  12.  
  13. #ifdef CURSES
  14.  
  15. /* The following is a curses emulation package suitable for the rogue program
  16.  * in which it is included.  No other suitability is claimed or suspected.
  17.  * Only those routines currently needed by this rogue program are included.
  18.  * This is being provided for those systems that don't have a suitable
  19.  * curses package and want to run this rogue program.
  20.  *
  21.  * Compile the entire program with -DCURSES to incorporate this package.
  22.  *
  23.  * The following is NOT supported:
  24.  *   "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string.
  25.  *   Terminals in which the cursor motion addresses the row differently from
  26.  *       the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y"
  27.  *   Termcap database stored in the TERMCAP environ variable as returned
  28.  *       from md_getenv().  Only the termcap file name can be stored there.
  29.  *       See the comments for md_getenv() in machdep.c.
  30.  *   Terminals without non-destructive backspace.  Backspace (^H) is used
  31.  *       for cursor motion regardless of any termcap entries.
  32.  *   The ":tc=" termcap entry is ignored.
  33.  *
  34.  * Suggestions:
  35.  *   Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or
  36.  *      ":do=\n"  This will help cursor motion optimization.  If line-feed
  37.  *      won't work, then a short escape sequence will do.  Same goes for "up"
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include "rogue.h"
  42.  
  43. boolean tc_tname();
  44.  
  45. #define BS 010
  46. #define LF 012
  47. #define CR 015
  48. #define ESC '\033'
  49. #define TAB '\011'
  50.  
  51. #define ST_MASK 0x80
  52. #define BUFLEN 256
  53.  
  54. char terminal[DROWS][DCOLS];
  55. char buffer[DROWS][DCOLS];
  56. char *tc_file;
  57.  
  58. char cm_esc[16], cm_sep[16], cm_end[16];
  59. boolean cm_reverse = 0;
  60. boolean cm_two = 0;
  61. boolean cm_three = 0;
  62. boolean cm_char = 0;
  63. short cm_inc = 0;
  64.  
  65. boolean screen_dirty;
  66. boolean lines_dirty[DROWS];
  67. boolean buf_stand_out = 0;
  68. boolean term_stand_out = 0;
  69.  
  70. int LINES = DROWS, COLS = DCOLS;
  71. WINDOW scr_buf;
  72. WINDOW *curscr = &scr_buf;
  73.  
  74. char *CL = (char *) 0;
  75. char *CM = (char *) 0;
  76. char *UC = (char *) 0;
  77. char *DO = (char *) 0;
  78. char *VS = "";
  79. char *VE = "";
  80. char *TI = "";
  81. char *TE = "";
  82. char *SO = "";
  83. char *SE = "";
  84.  
  85. short cur_row, cur_col;
  86.  
  87. initscr()
  88. {
  89.     clear();
  90.     get_term_info();
  91.     printf("%s%s", TI, VS);
  92. }
  93.  
  94. endwin()
  95. {
  96.     printf("%s%s", TE, VE);
  97.     md_cbreak_no_echo_nonl(0);
  98. }
  99.  
  100. move(row, col)
  101. short row, col;
  102. {
  103.     curscr->_cury = row;
  104.     curscr->_curx = col;
  105.     screen_dirty = 1;
  106. }
  107.  
  108. mvaddstr(row, col, str)
  109. short row, col;
  110. char *str;
  111. {
  112.     move(row, col);
  113.     addstr(str);
  114. }
  115.  
  116. addstr(str)
  117. char *str;
  118. {
  119.     while (*str) {
  120.         addch((int) *str++);
  121.     }
  122. }
  123.  
  124. addch(ch)
  125. register int ch;
  126. {
  127.     short row, col;
  128.  
  129.     row = curscr->_cury;
  130.     col = curscr->_curx++;
  131.  
  132.     if (buf_stand_out) {
  133.         ch |= ST_MASK;
  134.     }
  135.     buffer[row][col] = (char) ch;
  136.     lines_dirty[row] = 1;
  137.     screen_dirty = 1;
  138. }
  139.  
  140. mvaddch(row, col, ch)
  141. short row, col;
  142. int ch;
  143. {
  144.     move(row, col);
  145.     addch(ch);
  146. }
  147.  
  148. refresh()
  149. {
  150.     register i, j, line;
  151.     short old_row, old_col, first_row;
  152.  
  153.     if (screen_dirty) {
  154.  
  155.         old_row = curscr->_cury;
  156.         old_col = curscr->_curx;
  157.         first_row = cur_row;
  158.  
  159.         for (i = 0; i < DROWS; i++) {
  160.             line = (first_row + i) % DROWS;
  161.             if (lines_dirty[line]) {
  162.                 for (j = 0; j < DCOLS; j++) {
  163.                     if (buffer[line][j] != terminal[line][j]) {
  164.                         put_char_at(line, j, buffer[line][j]);
  165.                     }
  166.                 }
  167.                 lines_dirty[line] = 0;
  168.             }
  169.         }
  170.         put_cursor(old_row, old_col);
  171.         screen_dirty = 0;
  172.         fflush(stdout);
  173.     }
  174. }
  175.  
  176. wrefresh(scr)
  177. WINDOW *scr;
  178. {
  179.     short i, col;
  180.  
  181.     printf("%s", CL);
  182.     cur_row = cur_col = 0;
  183.  
  184.     for (i = 0; i < DROWS; i++) {
  185.         col = 0;
  186.         while (col < DCOLS) {
  187.             while ((col < DCOLS) && (buffer[i][col] == ' ')) {
  188.                 col++;
  189.             }
  190.             if (col < DCOLS) {
  191.                 put_cursor(i, col);
  192.             }
  193.             while ((col < DCOLS) && (buffer[i][col] != ' ')) {
  194.                 put_st_char((int) buffer[i][col]);
  195.                 cur_col++;
  196.                 col++;
  197.             }
  198.         }
  199.     }
  200.     put_cursor(curscr->_cury, curscr->_curx);
  201.     fflush(stdout);
  202.     scr = scr;        /* make lint happy */
  203. }
  204.  
  205. mvinch(row, col)
  206. short row, col;
  207. {
  208.     move(row, col);
  209.     return((int) buffer[row][col]);
  210. }
  211.  
  212. clear()
  213. {
  214.     printf("%s", CL);
  215.     fflush(stdout);
  216.     cur_row = cur_col = 0;
  217.     move(0, 0);
  218.     clear_buffers();
  219. }
  220.  
  221. clrtoeol()
  222. {
  223.     short row, col;
  224.  
  225.     row = curscr->_cury;
  226.  
  227.     for (col = curscr->_curx; col < DCOLS; col++) {
  228.         buffer[row][col] = ' ';
  229.     }
  230.     lines_dirty[row] = 1;
  231. }
  232.  
  233. standout()
  234. {
  235.     buf_stand_out = 1;
  236. }
  237.  
  238. standend()
  239. {
  240.     buf_stand_out = 0;
  241. }
  242.  
  243. crmode()
  244. {
  245.     md_cbreak_no_echo_nonl(1);
  246. }
  247.  
  248. noecho()
  249. {
  250.     /* crmode() takes care of this */
  251. }
  252.  
  253. nonl()
  254. {
  255.     /* crmode() takes care of this */
  256. }
  257.  
  258. clear_buffers()
  259. {
  260.     register i, j;
  261.  
  262.     screen_dirty = 0;
  263.  
  264.     for (i = 0; i < DROWS; i++) {
  265.         lines_dirty[i] = 0;
  266.         for (j = 0; j < DCOLS; j++) {
  267.             terminal[i][j] = ' ';
  268.             buffer[i][j] = ' ';
  269.         }
  270.     }
  271. }
  272.  
  273. put_char_at(row, col, ch)
  274. register row, col, ch;
  275. {
  276.     put_cursor(row, col);
  277.     put_st_char(ch);
  278.     terminal[row][col] = (char) ch;
  279.     cur_col++;
  280. }
  281.  
  282. put_cursor(row, col)
  283. register row, col;
  284. {
  285.     register i, rdif, cdif;
  286.     short ch, t;
  287.  
  288.     rdif = (row > cur_row) ? row - cur_row : cur_row - row;
  289.     cdif = (col > cur_col) ? col - cur_col : cur_col - col;
  290.  
  291.     if (((row > cur_row) && DO) || ((cur_row > row) && UC)) {
  292.         if ((rdif < 4) && (cdif < 4)) {
  293.             for (i = 0; i < rdif; i++) {
  294.                 printf("%s", ((row < cur_row) ? UC : DO));
  295.             }
  296.             cur_row = row;
  297.             if (col == cur_col) {
  298.                 return;
  299.             }
  300.         }
  301.     }
  302.     if (row == cur_row) {
  303.         if (cdif <= 6) {
  304.         for (i = 0; i < cdif; i++) {
  305.                 ch = (col < cur_col) ? BS :
  306.                         terminal[row][cur_col + i];
  307.                 put_st_char((int) ch);
  308.             }
  309.             cur_row = row;
  310.             cur_col = col;
  311.             return;
  312.         }
  313.     }
  314.     cur_row = row;
  315.     cur_col = col;
  316.  
  317.     row += cm_inc;
  318.     col += cm_inc;
  319.  
  320.     if (cm_reverse) {
  321.         t = row;
  322.         row = col;
  323.         col = t;
  324.     }
  325.     if (cm_two) {
  326.         printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end);
  327.     } else if (cm_three) {
  328.         printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end);
  329.     } else if (cm_char) {
  330.         printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end);
  331.     } else {
  332.         printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end);
  333.     }
  334. }
  335.  
  336. put_st_char(ch)
  337. register ch;
  338. {
  339.     if ((ch & ST_MASK) && (!term_stand_out)) {
  340.         ch &= ~ST_MASK;
  341.         printf("%s%c", SO, ch);
  342.         term_stand_out = 1;
  343.     } else if ((!(ch & ST_MASK)) && term_stand_out) {
  344.         printf("%s%c", SE, ch);
  345.         term_stand_out = 0;
  346.     } else {
  347.         ch &= ~ST_MASK;
  348.         putchar(ch);
  349.     }
  350. }
  351.  
  352. get_term_info()
  353. {
  354.     FILE *fp;
  355.     char *term, *tcf;
  356.     char buf[BUFLEN];
  357.  
  358.     if (tcf = md_getenv("TERMCAP")) {
  359.         if (strlen(tcf) > 40) {
  360.             clean_up("TERMCAP file name too long");
  361.         }
  362.         tc_file = tcf;
  363.     } else {
  364.         if (!(tc_file = md_gdtcf())) {
  365.             clean_up("I need a termcap file");
  366.         }
  367.     }
  368.  
  369.     if (!(term = md_getenv("TERM"))) {
  370.         clean_up("Cannot find TERM variable in environ");
  371.     }
  372.     if ((fp = fopen(tc_file, "r")) == NULL) {
  373.         sprintf(buf, "Cannot open TERMCAP file: %s", tc_file);
  374.         clean_up(buf);
  375.     }
  376.  
  377.     if (!tc_tname(fp, term, buf)) {
  378.         sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term,
  379.             tc_file);
  380.         clean_up(buf);
  381.     }
  382.     tc_gtdata(fp, buf);
  383.     fclose(fp);
  384. }
  385.  
  386. boolean
  387. tc_tname(fp, term, buf)
  388. FILE *fp;
  389. char *term;
  390. char *buf;
  391. {
  392.     short i, j;
  393.     boolean found = 0;
  394.     char *fg;
  395.  
  396.     while (!found) {
  397.         i = 0;
  398.         fg = fgets(buf, BUFLEN, fp);
  399.         if (fg != NULL) {
  400.             if (    (buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) &&
  401.                     (buf[0] != CR) && (buf[0] != LF)) {
  402.                 while (buf[i] && (!found)) {
  403.                     j = 0;
  404.                     while (buf[i] == term[j]) {
  405.                         i++;
  406.                         j++;
  407.                     }
  408.                     if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) {
  409.                         found = 1;
  410.                     } else {
  411.                         while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) {
  412.                             i++;
  413.                         }
  414.                         if (buf[i]) {
  415.                             i++;
  416.                         }
  417.                     }
  418.                 }
  419.             }
  420.         } else {
  421.             break;
  422.         }
  423.     }
  424.     return(found);
  425. }
  426.  
  427. tc_gtdata(fp, buf)
  428. FILE *fp;
  429. char *buf;
  430. {
  431.     short i;
  432.     boolean first = 1;
  433.  
  434.     do {
  435.         if (!first) {
  436.             if ((buf[0] != TAB) && (buf[0] != ' ')) {
  437.                 break;
  438.             }
  439.         }
  440.         first = 0;
  441.         i = 0;
  442.         while (buf[i]) {
  443.             while (buf[i] && (buf[i] != ':')) {
  444.                 i++;
  445.             }
  446.             if (buf[i] == ':') {
  447.                 if (!strncmp(buf + i, ":cl=", 4)) {
  448.                     tc_gets(buf + i, &CL);
  449.                 } else if (!strncmp(buf + i, ":cm=", 4)) {
  450.                     tc_gets(buf + i, &CM);
  451.                 } else if (!strncmp(buf + i, ":up=", 4)) {
  452.                     tc_gets(buf + i, &UC);
  453.                 } else if (!strncmp(buf + i, ":do=", 4)) {
  454.                     tc_gets(buf + i, &DO);
  455.                 } else if (!strncmp(buf + i, ":vs=", 4)) {
  456.                     tc_gets(buf + i, &VS);
  457.                 } else if (!strncmp(buf + i, ":ve=", 4)) {
  458.                     tc_gets(buf + i, &VE);
  459.                 } else if (!strncmp(buf + i, ":ti=", 4)) {
  460.                     tc_gets(buf + i, &TI);
  461.                 } else if (!strncmp(buf + i, ":te=", 4)) {
  462.                     tc_gets(buf + i, &TE);
  463.                 } else if (!strncmp(buf + i, ":vs=", 4)) {
  464.                     tc_gets(buf + i, &VS);
  465.                 } else if (!strncmp(buf + i, ":ve=", 4)) {
  466.                     tc_gets(buf + i, &VE);
  467.                 } else if (!strncmp(buf + i, ":so=", 4)) {
  468.                     tc_gets(buf + i, &SO);
  469.                 } else if (!strncmp(buf + i, ":se=", 4)) {
  470.                     tc_gets(buf + i, &SE);
  471.                 } else if (!strncmp(buf + i, ":li#", 4)) {
  472.                     tc_gnum(buf + i, &LINES);
  473.                 } else if (!strncmp(buf + i, ":co#", 4)) {
  474.                     tc_gnum(buf + i, &COLS);
  475.                 }
  476.                 i++;
  477.             }
  478.         }
  479.     } while (fgets(buf, BUFLEN, fp) != NULL);
  480.  
  481.     if ((!CM) || (!CL)) {
  482.         clean_up("Terminal and termcap must have cm and cl");
  483.     }
  484.     tc_cmget();
  485. }
  486.  
  487. tc_gets(ibuf, tcstr)
  488. char *ibuf;
  489. char **tcstr;
  490. {
  491.     short i, j, k, n;
  492.     char obuf[BUFLEN];
  493.  
  494.     i = 4;
  495.     j = 0;
  496.  
  497.     while (ibuf[i] && is_digit(ibuf[i])) {
  498.         i++;
  499.     }
  500.  
  501.     while (ibuf[i] && (ibuf[i] != ':')) {
  502.         if (ibuf[i] == '\\') {
  503.             i++;
  504.             switch(ibuf[i]) {
  505.             case 'E':
  506.                 obuf[j] = ESC;
  507.                 i++;
  508.                 break;
  509.             case 'n':
  510.                 obuf[j] = LF;
  511.                 i++;
  512.                 break;
  513.             case 'r':
  514.                 obuf[j] = CR;
  515.                 i++;
  516.                 break;
  517.             case 'b':
  518.                 obuf[j] = BS;
  519.                 i++;
  520.                 break;
  521.             case 't':
  522.                 obuf[j] = TAB;
  523.                 i++;
  524.                 break;
  525.             case '0':
  526.             case '1':
  527.             case '2':
  528.             case '3':
  529.             case '4':
  530.             case '5':
  531.             case '6':
  532.             case '7':
  533.             case '8':
  534.             case '9':
  535.                 n = 0;
  536.                 k = 0;
  537.                 while (k < 3 && ibuf[i] && is_digit(ibuf[i])) {
  538.                     n = (8 * n) + (ibuf[i] - '0');
  539.                     i++;
  540.                     k++;
  541.                 }
  542.                 obuf[j] = (char) n;
  543.                 break;
  544.             default:
  545.                 obuf[j] = ibuf[i];
  546.                 i++;
  547.             }
  548.         } else if (ibuf[i] == '^') {
  549.             obuf[j] = ibuf[i+1] - 64;
  550.             i += 2;
  551.         } else {
  552.             obuf[j] = ibuf[i++];
  553.         }
  554.         j++;
  555.     }
  556.     obuf[j] = 0;
  557.     if (!(*tcstr = md_malloc(j + 1))) {
  558.         clean_up("cannot alloc() memory");
  559.     }
  560.     strcpy(*tcstr, obuf);
  561. }
  562.  
  563. tc_gnum(ibuf, n)
  564. char *ibuf;
  565. int *n;
  566. {
  567.     short i;
  568.     int r = 0;
  569.  
  570.     i = 4;
  571.  
  572.     while (is_digit(ibuf[i])) {
  573.         r = (r * 10) + (ibuf[i] - '0');
  574.         i++;
  575.     }
  576.     *n = r;
  577. }
  578.  
  579. tstp()
  580. {
  581.     endwin();
  582.     md_tstp();
  583.  
  584.     start_window();
  585.     printf("%s%s", TI, VS);
  586.     wrefresh(curscr);
  587.     md_slurp();
  588. }
  589.  
  590. tc_cmget()
  591. {
  592.     short i = 0, j = 0, rc_spec = 0;
  593.  
  594.     while (CM[i] && (CM[i] != '%') && (j < 15)) {
  595.         cm_esc[j++] = CM[i++];
  596.     }
  597.     cm_esc[j] = 0;
  598.  
  599.     while (CM[i] && (rc_spec < 2)) {
  600.         if (CM[i] == '%') {
  601.             i++;
  602.             switch(CM[i]) {
  603.             case 'd':
  604.                 rc_spec++;
  605.                 break;
  606.             case 'i':
  607.                 cm_inc = 1;
  608.                 break;
  609.             case '2':
  610.                 cm_two = 1;
  611.                 rc_spec++;
  612.                 break;
  613.             case '3':
  614.                 cm_three = 1;
  615.                 rc_spec++;
  616.                 break;
  617.             case '.':
  618.                 cm_char = 1;
  619.                 rc_spec++;
  620.                 break;
  621.             case 'r':
  622.                 cm_reverse = 1;
  623.                 break;
  624.             case '+':
  625.                 i++;
  626.                 cm_inc = CM[i];
  627.                 cm_char = 1;
  628.                 rc_spec++;
  629.                 break;
  630.             }
  631.             i++;
  632.         } else {
  633.             j = 0;
  634.             while (CM[i] && (CM[i] != '%')) {
  635.                 cm_sep[j++] = CM[i++];
  636.             }
  637.             cm_sep[j] = 0;
  638.         }
  639.     }
  640.  
  641.     j = 0;
  642.     if (rc_spec == 2) {
  643.         while (CM[i] && (j < 15)) {
  644.             cm_end[j++] = CM[i++];
  645.         }
  646.     }
  647.     cm_end[j] = 0;
  648. }
  649.  
  650. #endif CURSES
  651.